/********************************************************************
	filename: 	Rectangle2D.cpp
	created:	2010/04/18
	author:		Xiuwei Chen

	purpose:	Implement of class 2D rectangle

	All rights Reserved
*********************************************************************/

#include "Rectangle2D.h"


/// <Summary>
/// Zero of Rectangle2D
/// </Summary>
const Rectangle2D Rectangle2D::Zero = Rectangle2D(0, 0, 0, 0);


/// <Summary>
/// default constructor
/// </Summary>
Rectangle2D::Rectangle2D()
	: x0(0), y0(0), x1(0), y1(0)
{
}

/// <Summary>
/// copy constructor
/// </Summary>
Rectangle2D::Rectangle2D(const Rectangle2D &rect)
	: x0(rect.x0), y0(rect.y0), x1(rect.x1), y1(rect.y1)
{
}

/// <Summary>
/// constructor
/// </Summary>
Rectangle2D::Rectangle2D(double _x0, double _y0, double _x1, double _y1)
	: x0(std::min(_x0, _x1)), y0(std::min(_y0, _y1)), x1(std::max(_x0, _x1)), y1(std::max(_y0, _y1))
{
}

/// <Summary>
/// constructor
/// </Summary>
Rectangle2D::Rectangle2D(const Point2D &p0, const Point2D &p1)
	: x0(std::min(p0.x, p1.x)), y0(std::min(p0.y, p1.y)), x1(std::max(p0.x, p1.x)), y1(std::max(p0.y, p1.y))
{
}

/// <Summary>
/// set value
/// </Summary>
void Rectangle2D::SetValue(double _x0, double _y0, double _x1, double _y1)
{
	x0 = std::min(_x0, _x1);
	x1 = std::max(_x0, _x1);
	y0 = std::min(_y0, _y1);
	y1 = std::max(_y0, _y1);
}

/// <Summary>
/// set value
/// </Summary>
void Rectangle2D::SetValue(const Point2D &p0, const Point2D &p1)
{
	x0 = std::min(p0.x, p1.x);
	x1 = std::max(p0.x, p1.x);
	y0 = std::min(p0.y, p1.y);
	y1 = std::max(p0.y, p1.y);
}

/// <Summary>
/// overload operation: assignment
/// </Summary>
Rectangle2D & Rectangle2D::operator = (const Rectangle2D &rect)
{
	x0 = rect.x0;
	x1 = rect.x1;
	y0 = rect.y0;
	y1 = rect.y1;
	return *this;
}

/// <Summary>
/// overload operation: "=="
/// </Summary>
bool Rectangle2D::operator == (const Rectangle2D &rect) const
{
	return x0 == rect.x0
		&& x1 == rect.x1
		&& y0 == rect.y0
		&& y1 == rect.y1;
}

/// <Summary>
/// overload operation: "!="
/// </Summary>
bool Rectangle2D::operator != (const Rectangle2D &rect) const
{
	return x0 != rect.x0
		|| x1 != rect.x1
		|| y0 != rect.y0
		|| y1 != rect.y1;
}

/// <Summary>
/// overload operation: "<"
/// </Summary>
bool Rectangle2D::operator < (const Rectangle2D &rect) const
{
	if(x0 == rect.x0 && y0 == rect.y0)
	{
		if(x1 == rect.x1) return y1 < rect.y1;
		else return x1 < rect.x1;
	}
	else
	{
		if(x0 == rect.x0) return y0 < rect.y0;
		else return x0 < rect.x0;
	}
}

/// <Summary>
/// overload operation: "+"
/// </Summary>
Rectangle2D Rectangle2D::operator + (const Rectangle2D &rect) const
{
	return Rectangle2D(
		std::min(x0, rect.x0),
		std::min(y0, rect.y0),
		std::max(x1, rect.x1),
		std::max(y1, rect.y1)
		);
}

/// <Summary>
/// overload operation: "+="
/// </Summary>
Rectangle2D & Rectangle2D::operator += (const Rectangle2D &rect)
{
	if(rect.x0 < x0) x0 = rect.x0;
	if(rect.y0 < y0) y0 = rect.y0;
	if(rect.x1 < x1) x1 = rect.x1;
	if(rect.y1 < y1) y1 = rect.y1;
	return *this;
}

/// <Summary>
/// Translation by 2D vector
/// </Summary>
void Rectangle2D::Translation(const Vector2D &v)
{
	x0 += v.x;
	x1 += v.x;
	y0 += v.y;
	y1 += v.y;
}

/// <Summary>
/// 2D rectangle Normalize
/// </Summary>
void Rectangle2D::Normalize()
{
	if(x1 > x0)
	{
		std::swap(x0, x1);
	}
	if(y1 > y0)
	{
		std::swap(y0, y1);
	}
}

/// <Summary>
/// Height (Y Axis)
/// </Summary>
double Rectangle2D::Height() const
{
	return y1 - y0;
}

/// <Summary>
/// Width (X Axis)
/// </Summary>
double Rectangle2D::Width() const
{
	return x1 - x0;
}

/// <Summary>
/// Area
/// </Summary>
double Rectangle2D::Area() const
{
	return (x1 - x0) * (y1 - y0);
}

/// <Summary>
/// Center
/// </Summary>
Point2D Rectangle2D::Center() const
{
	return Point2D(x0 + (x1 - x0) / 2, y0 + (y1 - y0) / 2);
}

/// <Summary>
/// merge rectangle
/// </Summary>
void Rectangle2D::Merge(const Rectangle2D &rect)
{
	if(rect.x0 < x0) x0 = rect.x0;
	if(rect.y0 < y0) y0 = rect.y0;
	if(rect.x1 < x1) x1 = rect.x1;
	if(rect.y1 < y1) y1 = rect.y1;
}